package com.idealighter.game.games.blackjack.manager;

import com.alibaba.fastjson.TypeReference;

import com.google.inject.Inject;
import com.google.inject.Singleton;

import com.idealighter.game.core.common.Game;
import com.idealighter.game.dictionary.domain.BlackjackRoomDomain;
import com.idealighter.game.games.blackjack.struct.BlackjackCardSeat;
import com.idealighter.game.games.blackjack.struct.BlackjackCardsTypeAndPoint;
import com.idealighter.game.games.blackjack.struct.BlackjackCardsTypeComparator;
import com.idealighter.game.games.blackjack.struct.BlackjackCardsTypeGetter;
import com.idealighter.game.games.blackjack.struct.BlackjackRoom;
import com.idealighter.game.games.blackjack.struct.BlackjackSeat;
import com.idealighter.game.games.blackjack.struct.BlackjackTable;
import com.idealighter.game.prizepool.manager.RoomPrizePoolMgrScript;
import com.idealighter.game.prizepool.struct.control.BlackjackControl;
import com.idealighter.game.prizepool.struct.room.ControlStrategy;
import com.idealighter.game.prizepool.struct.room.RoomPrizePool;
import com.idealighter.utils.check.EmptyUtil;
import com.idealighter.utils.code.RandCodeUtil;

import java.util.ArrayList;
import java.util.List;

import lombok.extern.slf4j.Slf4j;

@Singleton
@Slf4j
public class BlackjackControlScript {

  private static final TypeReference<BlackjackControl> BLACKJACK_CONTROL_TYPE =
      new TypeReference<BlackjackControl>() {};

  @Inject
  private RoomPrizePoolMgrScript roomPrizePoolMgr;


  /**
   * 模拟校验牌型最后输赢 .
   *
   * @author abin
   * @date 2018年3月30日 下午8:35:20
   * @param table 桌子信息.
   * @param blackjackCardsTypeAndPoint 待模拟牌型.
   * @return 结果筹码.
   */
  private long billCheckWin(BlackjackTable table,
      BlackjackCardsTypeAndPoint blackjackCardsTypeAndPoint) {
    // 玩家结算
    long tempWin = table.getSysWin();
    for (BlackjackSeat seat : table.getSeats()) {
      if (seat.isHasBet()) {
        for (BlackjackCardSeat cardSeat : seat.getCardSeats()) {
          if (!cardSeat.isBill()) { // 未结算

            int result = BlackjackCardsTypeComparator.compare(blackjackCardsTypeAndPoint,
                cardSeat.getCardTypeAndPoint());
            long winChips = 0;
            if (result == -1) { // 庄家输
              int multiple = BlackjackCardsTypeGetter
                  .multipleCheck(cardSeat.getCardTypeAndPoint().getCardsType());
              winChips += cardSeat.getBet() * multiple / BlackjackCardsTypeGetter.MULTIPLE_RATE;

            } else if (result == 0) { // 平
              winChips = cardSeat.getBet();
            } else { // 庄家赢
              winChips = 0;
            }
            tempWin += winChips - cardSeat.getBet();;
          }
        }
      }
    }
    return tempWin;
  }

  /**
   * 查找合适的牌型 .
   *
   * @author abin
   * @date 2018年3月30日 下午8:35:09
   * @param controlWin 控制输赢.
   * @param table 桌子.
   * @return 适合牌型.
   */
  private List<BlackjackCardsTypeAndPoint> suitCardType(boolean controlWin, BlackjackTable table) {
    List<BlackjackCardsTypeAndPoint> cardsTypeAndPoints = new ArrayList<>();
    for (BlackjackCardsTypeAndPoint typeAndPoint : BlackjackCardsTypeGetter.BANKER_CARD_TYPES) {
      long billChips = billCheckWin(table, typeAndPoint);
      boolean billWin = billChips > 0;
      if (controlWin && billWin) {
        cardsTypeAndPoints.add(typeAndPoint);
      } else if (!controlWin && !billWin) {
        cardsTypeAndPoints.add(typeAndPoint);
      }
    }
    return cardsTypeAndPoints;
  }



  /**
   * 只控制庄家最后的牌 .
   *
   * @author abin
   * @date 2018年3月30日 上午9:53:04
   */
  public void controlBankerLastCard(BlackjackTable table) {
    RoomPrizePool prizePool =
        roomPrizePoolMgr.defaultRoomPrizePool(Game.BLACK_JACK, table.getRoom().getId());

    ControlStrategy strategy = null;
    if (prizePool != null) {
      strategy = prizePool.abledControlStrategy();
    }

    BlackjackControl control = null;
    if (strategy != null) { // 房间奖池控制策略
      control = strategy.control(BLACKJACK_CONTROL_TYPE);
    }

    // 随机输赢
    boolean controlWin = control != null ? RandCodeUtil
        .random(control.getLoseRatio() + control.getWinRatio()) >= control.getLoseRatio()
        : RandCodeUtil.randomBoolean();

    log.info("[21点]({}) 控制 win={}", table.getId(), controlWin);

    List<BlackjackCardsTypeAndPoint> suitCardTypes = suitCardType(controlWin, table);

    if (EmptyUtil.listIsEmpty(suitCardTypes)
        || suitCardTypes.size() == BlackjackCardsTypeGetter.BANKER_CARD_TYPES.size()) {
      table.dealBankerCard();
    } else {
      table.dealBankerCard(suitCardTypes);
    }

  }

  /**
   * 筹码换算金币,只会是多个金币等于一个筹码.
   * 
   * @param roomDomain .
   * @param chips .
   */
  public long convertGold(BlackjackRoomDomain roomDomain, long chips) {
    return chips * roomDomain.getProportionGold() / roomDomain.getProportionChips();
  }

  /**
   * 结算房间奖池 .
   *
   * @param table .
   */
  public void balanceControl(BlackjackTable table) {
    BlackjackRoom room = table.getRoom();
    long gold = convertGold(room.getRoomDomain(), table.getSysWin());
    RoomPrizePool roomPrizePool =
        roomPrizePoolMgr.defaultRoomPrizePool(Game.BLACK_JACK, table.getRoom().getId());
    if (roomPrizePool != null) {
      roomPrizePool.getPrize().addAndGet(gold);
    }
  }

}
